package d7_thread_communicate;

import lombok.Data;

@Data//提供一下get和set方法
//共享资源desk
public class Desk {
    //定义一个实例变量记录包子
    private String data;


    //消费者进行吃包子
    //1、第一步:保证线程安全 加synchronized
    //消费者: 小懒猪, 姬紫月
    //桌子是唯一锁

    /**
     *
     * //有可能,吃包子的那个,会唤醒另外一个消费者,消费者判断是没有了包子(就是共享资源)
     *     //这时候,可能又唤醒了吃包子的另外一个,可能这两个一直在交替,
     *     //现在我们没有学习,批量等待的技术,无法进行批量等待
     *     //生产者还是有机会抢到锁的
     */
    public synchronized void get() throws Exception {
        //2、获取当前吃包子的线程是谁
        String name = Thread.currentThread().getName();
        //3、判断是否有包子
        //3.1证明是没有包子
        if (data == null) {
//            System.out.println("==没有包子==");
            //3.2唤醒生产者线程,进行生产包子(可能唤醒的还是消费者)
            //3.2.1先唤醒别的线程
            //注意只有桌子才知道,谁占用了它,说以唤醒的方法要使用坐桌子
            //-----------//不管对面醒没醒,都要按照流程来,唤醒它-------------
            /**
             * //一定是先唤醒别人,在等待自己(例子:不可以把自己搞晕了,在去叫别人)
             *     //只有桌子才知道谁占用了它,只有桌子才知道,谁是因为占用它才停止的
             *     //桌子是一个通信的信号(这是官方的规定,不这样操作,就会崩)
             */
            this.notifyAll();//唤醒所有线程,让他们去争取桌子的使用全
            //当前线程进行入等待
            this.wait();
        } else {
            //3.3 证明桌子上是有包子的
            //3.3.1 进行吃包子的操作
            System.out.println(name + "吃掉了=====>" + data);
            //3.3.1 更新共享资源
            data = null;//直接置为null
            this.notifyAll();
            this.wait();
        }
    }

    //1、首先考虑线程安全问题
    //1.1线程通向的首要,就是要做到线程安全
    //生产者: 叶凡 陈平安 秦牧
    public synchronized void set() throws Exception {
        //2、获取当前生产的线程
        String name = Thread.currentThread().getName();

        //3、判断是否有包子
        if (data == null) {
//            System.out.println("==没有包子,但正在生产==");
            //4、桌子上是沒有包子,进行生产
            data = name + "====>生产的大肉包子";
            System.out.println(data);
            //5、唤醒其他线程
            this.notifyAll();
            //6、让当前线程等待并释放所占锁, 直到线程调用notify方法或者notifyAll()方法
            this.wait();
        } else {
            //7、有包子,无序生产
            //8、唤醒正在等待的所有线程
            this.notifyAll();
            //9、让当前线程等待并释放所占锁, 直到线程调用notify()方法或者notifyAll()方法
            this.wait();
        }

    }
}
